﻿#include "MirTextBox.h"
#include "../Program.h"
#include "../Forms/Client.CMain.h"
#include "MirMessageBox.h"
#include "MirInputBox.h"
#include "MirAmountBox.h"
#include "MirScene.h"

using namespace Client::MirGraphics;
using namespace SlimDX;
using namespace SlimDX::Direct3D9;

namespace Client::MirControls
{

    void MirTextBox::OnBackColourChanged()
    {
        MirControl::OnBackColourChanged();
        if (TextBox != nullptr && !TextBox->IsDisposed)
        {
            TextBox->BackColor = getBackColour();
        }
    }

    void MirTextBox::OnEnabledChanged()
    {
        MirControl::OnEnabledChanged();
        if (TextBox != nullptr && !TextBox->IsDisposed)
        {
            TextBox->Enabled = getEnabled();
        }
    }

    void MirTextBox::OnForeColourChanged()
    {
        MirControl::OnForeColourChanged();
        if (TextBox != nullptr && !TextBox->IsDisposed)
        {
            TextBox->ForeColor = getForeColour();
        }
    }

    void MirTextBox::OnLocationChanged()
    {
        MirControl::OnLocationChanged();
        if (TextBox != nullptr && !TextBox->IsDisposed)
        {
            TextBox->Location = getDisplayLocation();
        }

        TextureValid = false;
        Redraw();
    }

    int MirTextBox::getMaxLength() const
    {
        if (TextBox != nullptr && !TextBox->IsDisposed)
        {
            return TextBox->MaxLength;
        }
        return -1;
    }

    void MirTextBox::setMaxLength(int value)
    {
        if (TextBox != nullptr && !TextBox->IsDisposed)
        {
            TextBox->MaxLength = value;
        }
    }

    void MirTextBox::OnParentChanged()
    {
        MirControl::OnParentChanged();
        if (TextBox != nullptr && !TextBox->IsDisposed)
        {
            OnVisibleChanged();
        }
    }

    bool MirTextBox::getPassword() const
    {
        if (TextBox != nullptr && !TextBox->IsDisposed)
        {
            return TextBox->UseSystemPasswordChar;
        }
        return false;
    }

    void MirTextBox::setPassword(bool value)
    {
        if (TextBox != nullptr && !TextBox->IsDisposed)
        {
            TextBox->UseSystemPasswordChar = value;
        }
    }

    System::Drawing::Font *MirTextBox::getFont() const
    {
        if (TextBox != nullptr && !TextBox->IsDisposed)
        {
            return TextBox->Font;
        }
        return nullptr;
    }

    void MirTextBox::setFont(System::Drawing::Font *value)
    {
        if (TextBox != nullptr && !TextBox->IsDisposed)
        {
            TextBox->Font = ScaleFont(value);
        }
    }

    void MirTextBox::OnSizeChanged()
    {
        TextBox->Size = getSize();

        DisposeTexture();

        _size = getSize();

        if (TextBox != nullptr && !TextBox->IsDisposed)
        {
            MirControl::OnSizeChanged();
        }
    }

    std::string MirTextBox::getText() const
    {
        if (TextBox != nullptr && !TextBox->IsDisposed)
        {
            return TextBox->Text;
        }
        return "";
    }

    void MirTextBox::setText(const std::string &value)
    {
        if (TextBox != nullptr && !TextBox->IsDisposed)
        {
            TextBox->Text = value;
        }
    }

    std::vector<std::string> MirTextBox::getMultiText() const
    {
        if (TextBox != nullptr && !TextBox->IsDisposed)
        {
            return TextBox->Lines;
        }
        return std::vector<std::string>();
    }

    void MirTextBox::setMultiText(const std::vector<std::string> &value)
    {
        if (TextBox != nullptr && !TextBox->IsDisposed)
        {
            TextBox->Lines = value;
        }
    }

    bool MirTextBox::getVisible() const
    {
        return MirControl::getVisible();
    }

    void MirTextBox::setVisible(bool value)
    {
        MirControl::setVisible(value);
        OnVisibleChanged();
    }

    void MirTextBox::OnVisibleChanged()
    {
        MirControl::OnVisibleChanged();

        if (TextBox != nullptr && !TextBox->IsDisposed)
        {
            TextBox->Visible = getVisible();
        }
    }

    void MirTextBox::TextBox_VisibleChanged(std::any sender, EventArgs *e)
    {
        DialogChanged();

        if (TextBox->Visible && TextBox->CanFocus)
        {
            if (Program::Form->ActiveControl == nullptr || Program::Form->ActiveControl == Program::Form)
            {
                Program::Form->ActiveControl = TextBox;
            }
        }

        if (!TextBox->Visible)
        {
            if (Program::Form->ActiveControl == TextBox)
            {
                Program::Form->Focus();
            }
        }
    }

    void MirTextBox::SetFocus(std::any sender, EventArgs *e)
    {
        if (TextBox->Visible)
        {
            TextBox->VisibleChanged -= SetFocus;
        }
        if (TextBox->Parent != nullptr)
        {
            TextBox->ParentChanged -= SetFocus;
        }

        if (TextBox->CanFocus)
        {
            TextBox->Focus();
        }
        else if (TextBox->Visible && TextBox->Parent != nullptr)
        {
            Program::Form->ActiveControl = TextBox;
        }


    }

    void MirTextBox::MultiLine()
    {
        TextBox->Multiline = true;
        TextBox->Size = getSize();

        DisposeTexture();
        Redraw();
    }

    MirTextBox::MirTextBox() : TextBox(new TextBox();
        TextBox->BackColor = getBackColour();
        TextBox->BorderStyle = BorderStyle::None;
        TextBox->Font = new System::Drawing::Font(Settings::FontName, 10.0F * 96.0f / CMain::Graphics->DpiX);
        TextBox->ForeColor = getForeColour();
        TextBox->Location = getDisplayLocation();
        TextBox->Size = getSize();
        TextBox->Visible = getVisible();
        TextBox->Tag = this;
        TextBox->Cursor = CMain::Cursors[static_cast<unsigned char>(MouseCursor::TextPrompt)])
        {
        setBackColour(Color::Black);

        setDrawControlTexture(true);
        TextureValid = false;


        CaretPen = new Pen(getForeColour(), 1);

        TextBox->VisibleChanged += TextBox_VisibleChanged;
        TextBox->ParentChanged += TextBox_VisibleChanged;
        TextBox->KeyUp += TextBoxOnKeyUp;
        TextBox->KeyPress += TextBox_KeyPress;

        TextBox->KeyPress += TextBox_NeedRedraw;
        TextBox->KeyUp += TextBox_NeedRedraw;
        TextBox->MouseDown += TextBox_NeedRedraw;
        TextBox->MouseUp += TextBox_NeedRedraw;
        TextBox->LostFocus += TextBox_NeedRedraw;
        TextBox->GotFocus += TextBox_NeedRedraw;
        TextBox->MouseWheel += TextBox_NeedRedraw;

        Shown += MirTextBox_Shown;
        TextBox->MouseMove += CMain::CMain_MouseMove;
        }

    void MirTextBox::TextBox_NeedRedraw(std::any sender, EventArgs *e)
    {
        TextureValid = false;
        Redraw();
    }

    Point *MirTextBox::GetCaretPosition()
    {
        Point *result = TextBox->GetPositionFromCharIndex(TextBox->SelectionStart);

        if (result->X == 0 && TextBox->Text.Length > 0)
        {
            result = TextBox->GetPositionFromCharIndex(TextBox->Text.Length - 1);
            int s = result->X / TextBox->Text.Length;
            result->X = static_cast<int>(result->X + (s * 1.46));
            result->Y = TextBox->GetLineFromCharIndex(TextBox->SelectionStart) * TextBox->Font->Height;
        }

        return result;
    }

    void MirTextBox::TextBoxOnKeyUp(std::any sender, KeyEventArgs *e)
    {
        switch (e->KeyCode)
        {
            case Keys->PrintScreen:
                CMain::CMain_KeyUp(sender, e);
                break;

        }
    }

    void MirTextBox::TextBox_KeyPress(std::any sender, KeyPressEventArgs *e)
    {
        MirControl::OnKeyPress(e);

        if (e->KeyChar == static_cast<char>(Keys->Escape))
        {
            Program::Form->ActiveControl = nullptr;
            e->Handled = true;
        }
    }

    void MirTextBox::MirTextBox_Shown(std::any sender, EventArgs *e)
    {
        TextBox->Parent = Program::Form;
        CMain::Ctrl = false;
        CMain::Shift = false;
        CMain::Alt = false;
        CMain::Tilde = false;

        TextureValid = false;
        SetFocus();
    }

    void MirTextBox::SetFocus()
    {
        if (!TextBox->Visible)
        {
            TextBox->VisibleChanged += SetFocus;
        }
        else if (TextBox->Parent == nullptr)
        {
            TextBox->ParentChanged += SetFocus;
        }
        else
        {
            TextBox->Focus();
        }
    }

    void MirTextBox::DialogChanged()
    {
        MirMessageBox *box1 = nullptr;
        MirInputBox *box2 = nullptr;
        MirAmountBox *box3 = nullptr;

        if (MirScene::ActiveScene != nullptr && MirScene::ActiveScene->getControls().size() > 0)
        {
            box1 = static_cast<MirMessageBox*>(MirScene::ActiveScene->getControls().FirstOrDefault([&] (std::any ob)
            {
                dynamic_cast<MirMessageBox*>(ob) != nullptr;
            }));
            box2 = static_cast<MirInputBox*>(MirScene::ActiveScene->getControls().FirstOrDefault([&] (std::any O)
            {
                dynamic_cast<MirInputBox*>(O) != nullptr;
            }));
            box3 = static_cast<MirAmountBox*>(MirScene::ActiveScene->getControls().FirstOrDefault([&] (std::any ob)
            {
                dynamic_cast<MirAmountBox*>(ob) != nullptr;
            }));
        }


        if ((box1 != nullptr && box1 != getParent()) || (box2 != nullptr && box2 != getParent()) || (box3 != nullptr && box3 != getParent()))
        {
            TextBox->Visible = false;
        }
        else
        {
            TextBox->Visible = getVisible() && TextBox->Parent != nullptr;
        }
    }

    void MirTextBox::Dispose(bool disposing)
    {
        MirControl::Dispose(disposing);

        if (!disposing)
        {
            return;
        }

        if (!TextBox->IsDisposed)
        {
            TextBox->Dispose();
        }
    }
}
